module zl_2346_6(clk,rst_n,key_in,key_flag,key_state,cnt_out);//端口声明
input clk;        //时钟10kHz
input rst_n;      //复位信号
input key_in;     //按键输入
 
output key_state;    //按键状态，高电平为未按下，低电平为按下状态
output key_flag;     //完成滤波信号（消抖后的按键），这里有很有趣的一件事，我们在生活中发现，
							//有些按键是按下时产生效果的，有些是按下松开后起作用的，在这段代码中，依据这个信号来产生。
 output [11:0]cnt_out;
//定义
parameter   IDLE 		= 2'b00,
				FILTER0 	= 2'b01,
				DOWN 		= 2'b10,
				FILTER1	= 2'b11;
//内部信号声明
reg [1:0] state;
reg key_flag;
reg key_state;
reg cnt_full;
reg [7:0] cnt;
reg [11:0]cnt2;
reg [11:0]cnt_out;
reg en_counter;
reg en2_counter;

//边沿检测模块，将输入信号寄存一个节拍，分别按键上升沿和下降沿的产生
reg key_tmp0,key_tmp1;
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		key_tmp0 <= 1'b1;
		key_tmp1 <= 1'b1;
	end
	else 
	begin
		key_tmp0 <= key_in;
		key_tmp1 <= key_tmp0;
	end
end
wire pedge,nedge;
assign nedge = (!key_tmp0) &  key_tmp1;        //下降沿
assign pedge = key_tmp0  & (!key_tmp1);        //上升沿
 
//状态机模块
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			state <= IDLE;
			en_counter <= 1'b0;
			key_state <= 1'b1;
			key_flag <= 1'b0;
		end
	else 
	begin
		case(state)
			IDLE:
			begin
				key_flag <= 1'b0;
				key_state <= 1'b1;
				en_counter <= 1'b0;
				if(nedge)        //检测到下降沿，进入下一个状态同时打开计数器
					begin
						state <= FILTER0;
						en_counter <= 1'b1;
						en2_counter <= 1'b1;
						
					end
				else 
					state <= state;    
			end
			FILTER0:
				if(cnt_full)        //计数满，说明达到稳定状态，关闭计数器
					begin
						state <= DOWN;
						en_counter <= 1'b0;
						en2_counter <= 1'b0;
						key_flag <= 1'b1;
						key_state <= 1'b0;
					end
				else if(pedge)        //检测到上升沿（毛刺），跳回idle状态同时关闭计数器
						begin
							en_counter <= 1'b0;
							state <= IDLE;
						end
					 else 
					 	state <= state;
			DOWN:
				begin
					key_flag <= 1'b0;
					if(pedge)
						begin
							state <= FILTER1;
							en_counter <= 1'b1;
							en2_counter <= 1'b1;
						end
					else 
						state <= DOWN;
				end
			FILTER1:
				if(cnt_full)
					begin
						state <= IDLE;
						//key_flag <= 1'b1;
						en2_counter <= 1'b0;
						key_state <= 1'b0;
					end
				else 
					if(nedge)
						begin
					 		en_counter <= 1'b0;
					 		state <= DOWN;					 		
					 	end 
					else 
						state <= state;
			default:
				state <= IDLE;
			endcase
	end
end
 
//20ms计数器
//这里有一个计数使能信号，只有当计数使能为高电平的时候，计数器才会计数，数数到200计数满时间到
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		cnt <= 20'd0;
	else if(en_counter)
			cnt <= cnt + 1'b1;
		 else 
   		 	cnt <= 20'd0;
end
//计数满信号
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		cnt_full <= 1'b0;
	else if(cnt == 8'd200)
			cnt_full <= 1'b1;
		 else 
		 	cnt_full <= 1'b0;
end
 
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		cnt2<=12'b0;
		cnt_out<=12'd0;
		end
	else if(en2_counter)begin
			cnt2 <= cnt2 + 1'b1;
			cnt_out<=cnt2;
			end
	else begin
   		cnt2 <= 12'd0;
		end
end
 
endmodule 